/*********************************************************************************
 ***      Copyright:  (C) 2019 liushoujin<2398866942@qq.com>
 ***                  All rights reserved.
 ***
 ***       Filename:  tlv.serever.c
 ***    Description:  This file is tlv server 
 ***                 
 ***        Version:  1.0.0(2019年04月04日)
 ***         Author:  liushoujin <2398866942@qq.com>
 ***      ChangeLog:  1, Release initial version on "2019年04月04日 16时37分52秒"
 ***                 
 **********************************************************************************/
#include"tlv.server.h"

int g_stop=0;

void print_usage(const char *program_name)
{
    printf("%s --(2019.4.4)\n",program_name);
    printf("%s -i (client_ip) -p (client_port) -h (help)\n",program_name);
    printf("-i --ip   the ip of tlv client\n");
    printf("-p --port   the port of tlv client\n");
    printf("-h --help   the tlv_server how to use\n");
    return;
}

void sign_handler(int signum)
{
    g_stop=1;
    /*if(SIGTERM==signum)
    {   
        printf("SIGTERM signal detected\n");
        g_stop=1; 
    }   
    else if(SIGALRM==signum)
    {
        printf("SIGALRM signal detected\n");
        g_stop=1;
    }
    else if(SIGINT==signum)
    {
        printf("SIGINT signal detected\n");
        g_stop=1;
    }*/
}

void dns(char *domain_name,char **ip)
{
    struct hostent       *client_name=NULL;

    client_name=gethostbyname(domain_name);
    inet_ntop(client_name->h_addrtype,client_name->h_addr,*ip,32);
}

void set_socket_rlimit(void)
{
    struct rlimit limit={0};

    getrlimit(RLIMIT_NOFILE,&limit);
    limit.rlim_cur=limit.rlim_max;
    setrlimit(RLIMIT_NOFILE,&limit);

    printf("set socket open fd max count to %d\n",limit.rlim_max);
}

int main(int argc,char **argv)
{
    char           *program_name;
    int            opt=-1;
    char           *ip=NULL;
    char           *client_ip=(char *)malloc(32);
    struct sockaddr_in cliaddr;
    int            port=0;
    int            log_fd=-1;
    int            new_clifd=-1;
    int            rv=-1;
    int            client_fd=-1;
    int            on=1;
    char           buf[128];
    int            epollfd;
    struct epoll_event event;
    struct epoll_event event_array[512];
    int            events;
    int            i;

    program_name=basename(argv[0]);
    const char *short_opts="i:p:h";
    const struct option long_opts[]={
        {"ip",required_argument,NULL,'i'},
        {"port",required_argument,NULL,'p'},
        {"help",no_argument,NULL,'h'},
        {0,0,0,0}
    };

while((opt=getopt_long(argc,argv,short_opts,long_opts,NULL))!=-1)
{
    switch(opt)
    {
        case 'i':
            ip=optarg;
            dns(ip,&client_ip);
            break;
        case 'p':
            port=atoi(optarg);
            break;
        case 'h':
            print_usage(program_name);
            return 0;
    }
}                  
if(!client_ip ||  !port)
{
    print_usage(program_name);
    return 0;
}


signal(SIGTERM,sign_handler);
signal(SIGALRM,sign_handler);
signal(SIGINT,sign_handler);

log_fd = open("temper.log",O_CREAT|O_RDWR, 0666);
if (log_fd < 0)
{
    printf("Open the logfile failure : %s\n", strerror(errno));
    return 0;
}
           
dup2(log_fd, STDOUT_FILENO);
dup2(log_fd, STDERR_FILENO); 

if ((daemon(1, 1)) < 0)
{
    printf("Deamon failure : %s\n", strerror(errno));
    return 0;
}
            
while(!g_stop)
{
    client_fd = socket( AF_INET, SOCK_STREAM, 0); 
    if(client_fd < 0)
    {   
        printf("Fail to create a client socket [%d]: %s\n", client_fd, strerror(errno) );
        return -1; 
    }  
    printf("creat a client socket[%d] successufully!\n",client_fd);
    memset(&cliaddr, 0, sizeof(cliaddr));
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_port = htons(port);
    cliaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    setsockopt(client_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
        
    set_socket_rlimit();

    rv=bind(client_fd,(struct sockaddr*)&cliaddr,sizeof(cliaddr));
    if(rv<0)
    { 
        printf("socket [%d] bind on port [%d] failure:%s\n",client_fd,port,strerror(errno));
        return -1;
    }
    printf("socket [%d] bind on port [%d] successfully\n",client_fd,port);
    listen(client_fd,64);
    printf("start to listen port [%d]\n",port);

    if((epollfd=epoll_create(512))<0)
    {
        printf("epoll_creat() failure:%s\n",strerror(errno));
        return -1;
    }
       
    event.events=EPOLLIN;
    event.data.fd=client_fd;

    if(epoll_ctl(epollfd,EPOLL_CTL_ADD,client_fd,&event)<0)
    {
        printf("epoll add listen socket failure:%s\n",strerror(errno));
        return -1;
    }
        
    for(;;)
    {
    events=epoll_wait(epollfd,event_array,512,-1);
        if(events<0)
        {
            printf("epoll failure:%s\n",strerror(errno));
            break;
        }
        else if(events==0)
        {
            printf("epoll get time\n");
            continue;
        }
        for(i=0;i<events;i++)
        {
            if((event_array[i].events&EPOLLERR)||(event_array[i].events&EPOLLHUP))
            {
                printf("epoll_wait get errorr on fd [%d]:%s\n",event_array[i].data.fd,strerror(errno));
                epoll_ctl(epollfd,EPOLL_CTL_DEL,event_array[i].data.fd,NULL);
                close(event_array[i].data.fd);
            }
            if(event_array[i].data.fd==client_fd)
            {
                if((new_clifd=accept(client_fd,(struct sockaddr *)NULL,NULL))<0)
                {
                    printf("accept new client failure:%s\n",strerror(errno));
                    continue;
                }
                    printf("accept new client [%s:%d] successfully\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));

            event.data.fd=new_clifd;
            event.events=EPOLLIN;

               if(epoll_ctl(epollfd,EPOLL_CTL_ADD,new_clifd,&event)<0)
               {
                   printf("epoll add listen socket failure:%s\n",strerror(errno));
                   close(event_array[i].data.fd);
                   continue;
               }
                  printf("epoll add client socket [%d] ok\n",new_clifd);
            }
            else
            {
                rv=read(event_array[i].data.fd,buf,sizeof(buf));
                if(rv<=0)
                {
                    printf("read data from client by event_array[i].data.fd [%d] failure:%s\n",event_array[i].data.fd,strerror(errno));
                    epoll_ctl(epollfd,EPOLL_CTL_DEL,event_array[i].data.fd,NULL);
                    close(event_array[i].data.fd);
                    continue;
                }
                else
                {
                    printf("socket [%d] read %d bytes data from client\n",event_array[i].data.fd,rv);
                    dividepack(buf,sizeof(buf));
                    sleep(30);
                }
            }
        }
    }
}
free(client_ip);
close(new_clifd);
printf("program strat stop running...\n");
return 0;
}

